package com.zhss.demo.register.server;

import java.util.HashMap;
import java.util.Map;
import java.util.concurrent.locks.ReentrantReadWriteLock;
import java.util.concurrent.locks.ReentrantReadWriteLock.ReadLock;
import java.util.concurrent.locks.ReentrantReadWriteLock.WriteLock;

/**
 * @author 周成龙
 * @date 2021-01-25 10:47
 * description 服务注册表的双缓存机制，用来减少对锁的使用，提高并发量
 */
public class ServiceRegistryCache {
    //单例模式
    private static ServiceRegistryCache registryCache = new ServiceRegistryCache();

    private ServiceRegistryCache() {
        CacheSyncDaemon cacheSyncDaemon = new CacheSyncDaemon();
        cacheSyncDaemon.setDaemon(true);
        cacheSyncDaemon.start();
    }

    public static ServiceRegistryCache getInstance() {
        return registryCache;
    }

    //服务注册表
    ServiceRegistry registry = ServiceRegistry.getInstance();
    //只读缓存
    private Map<String, Object> readOnlyCache = new HashMap<String, Object>();
    //读写缓存
//    private Map<String,Object> readWriteCache=new HashMap<String, Object>();
    private volatile Boolean registryChangeFlag = true;
    public static final Long CACHE_SYNC_INTERVAL = 3 * 1000L;


    //拉取的注册表的类型，全量注册表和增量注册表
    enum RegistryType {
        FULL_REGISTER_SERVICE, DELTA_REGISTER_SERVICE
    }

    //读写锁，用于控制ReadOnlyCache的读写
    ReentrantReadWriteLock readWriteLock = new ReentrantReadWriteLock();
    //读锁
    ReadLock readLock = readWriteLock.readLock();
    //这把锁用于
    Byte[] lock = new Byte[0];

    //写锁
    WriteLock writeLock = readWriteLock.writeLock();

    /**
     * description 根据缓存key来获取数据
     *
     * @param cacheKey return
     *                 author 周成龙
     *                 createTime 2021/1/25 11:01
     **/
    public Object get(String cacheKey) {
        Object cacheValue = null;
        try {
            //对readOnlyCache加读锁
            readLock.lock();
            //从readOnlyCache中获取value
            cacheValue = readOnlyCache.get(cacheKey);
            if (cacheValue == null) {
                //这里使用synchronized主要是用来保证可见性
                synchronized (lock) {
                    if (readOnlyCache.get(cacheKey) == null) {
                        //这里从readOnlyCache中获取不到值，要去从readWriteCache中获取
//                        cacheValue = readWriteCache.get(cacheKey);
                        /*if(cacheValue==null){
                            //从真正的内存中获取
                            cacheValue=getCacheValue(cacheKey);
                            //将其放入readWriteCache中
                            readWriteCache.put(cacheKey,cacheValue);
                        }*/
                        cacheValue = null;
                        if (registryChangeFlag) {
                            cacheValue = getCacheValue(cacheKey);
                            registryChangeFlag = false;
                        }
                        readOnlyCache.put(cacheKey, cacheValue);
                    }
                }
            }
        } finally {
            readLock.unlock();
        }
        return cacheValue;
    }

    /**
     * description 获取实际的缓存数据
     *
     * @param cacheKey return
     *                 author 周成龙
     *                 createTime 2021/1/25 11:16
     **/
    public Object getCacheValue(String cacheKey) {
        try {
            registry.readLock();
            if (RegistryType.FULL_REGISTER_SERVICE.toString().equals(cacheKey)) {
                Applications applications = new Applications(registry.getRegistry());
                return applications.clone();
            } else if (RegistryType.DELTA_REGISTER_SERVICE.toString().equals(cacheKey)) {
                DeltaRegister deltaRegistry = registry.getDeltaRegistry();
                return deltaRegistry.clone();
            }
        }  catch (CloneNotSupportedException e) {
            e.printStackTrace();
        } finally {
            registry.unReadLock();
        }
        return null;
    }

    /**
     * description 将readWriteCache中的数据失效
     *
     * @param
     * @author 周成龙
     * createTime 2021/1/25 11:22
     **/
    public void invalidate() {
        synchronized (lock) {
            this.registryChangeFlag = true;
        }
    }

    /**
     * description 每个30秒检测一次ReadWriteCache是否是null，就是是注册表是否改变
     * author 周成龙
     * createTime 2021/1/25 11:26
     **/
    class CacheSyncDaemon extends Thread {
        @Override
        public void run() {
            try {
                while (true) {
                    try {
                        writeLock.lock();
                        synchronized (lock) {
                            if (registryChangeFlag) {
                                readOnlyCache.put(RegistryType.FULL_REGISTER_SERVICE.toString(), null);
                            }
                            writeLock.lock();
                            if (registryChangeFlag) {
                                readOnlyCache.put(RegistryType.DELTA_REGISTER_SERVICE.toString(), null);
                                writeLock.unlock();
                            }
                        }
                    } finally {
                        writeLock.unlock();
                    }

                    Thread.sleep(CACHE_SYNC_INTERVAL);
                }
            } catch (Exception e) {
                System.out.println(e.toString());
            }
        }
    }
}
